﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using System.Configuration;

namespace Sherwood
{
    /// <summary>
    /// Provides access to a dependency injection container which allows objects    
    /// from unreferenced assemblies to be instansiated at runtime.
    /// </summary>
    public class DependencyInjection
    {
        private static IUnityContainer _container;
        private static string _configurationFile;

        /// <summary>
        /// Returns the default IUnityContainer object.
        /// </summary>
        public static IUnityContainer Container
        {
            get
            {
                lock (typeof(DependencyInjection))
                {
                    if (_container == null)
                    {
                        _container = new UnityContainer();
                        ConfigureContainer();
                    }
                }
                return _container;
            }
        }


        /// <summary>
        /// Path to unity configuration file.
        /// </summary>
        public static string ConfigurationFile
        {
            get
            {
                if (_configurationFile == null)
                {
                    _configurationFile = ConfigurationManager.AppSettings["DependencyInjectionConfigurationFile"];
                }
                return _configurationFile;
            }
            set
            {
                lock (typeof(DependencyInjection))
                {
                    _configurationFile = value;
                    ConfigureContainer();
                }
            }
        }

        /// <summary>
        /// Resolves an instansiates an instance of the type configured for the specified interface.
        /// </summary>
        /// <typeparam name="TInterface">Interface to resolve type for</typeparam>
        /// <returns>Instance of object which implements I</returns>
        public static TInterface Resolve<TInterface>()
        {
            return Container.Resolve<TInterface>();
        }

        /// <summary>
        /// Resolves an instansiates an instance of the type configured for the specified interface.
        /// </summary>
        /// <typeparam name="TInterface">Interface to resolve type for</typeparam>
        /// <param name="name">The name of the instance to return</param>
        /// <returns>Instance of object which implements I</returns>
        public static TInterface Resolve<TInterface>(string name)
        {
            return Container.Resolve<TInterface>(name);
        }

        /// <summary>
        /// Internally used to create a new container based on configuration from a configuration file.
        /// </summary>
        protected static void ConfigureContainer()
        {
            if (_container != null)
            {

                if (!string.IsNullOrEmpty(ConfigurationFile))
                {
                    //Load from configuration file
                    string filePath = ConfigurationFile;
                    if (HttpContext.Current != null && HttpContext.Current.Server != null)
                    {
                        filePath = HttpContext.Current.Server.MapPath(filePath); 
                    }
                    if (System.IO.File.Exists(filePath))
                    {
                        var fileMap = new ExeConfigurationFileMap {ExeConfigFilename = filePath};
                        System.Configuration.Configuration configuration =
                            ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
                        var unitySection = (UnityConfigurationSection) configuration.GetSection("unity");
                        _container.LoadConfiguration(unitySection);
                    }
                    else
                    {
                        throw new Exception("Unity configuration file does not exist.");
                    }
                }
                else
                {
                    //Load from default configuration file (app.config / web.config)
                    _container.LoadConfiguration();
                }
            }
        }
    }
}
